<?php
require_once 'Zend/XmlRpc/Client.php';
require_once 'phpBlogApi/Exception.php';
require_once 'PhpBlogApi/ExtendedDriver.php';
require_once 'PhpBlogApi/Post.php';
/**
*   MetaWeblog using the metaWeblog API implementation to connect to wordpress or any blogs that support XML-RPC and the meteWeb API.
*   http://www.xmlrpc.com/metaWeblogApi
*
*   http://code.google.com/p/phpblogapi/
*
*   @category    Services
*   @package     PhpBlogApi
*   @author      Kao Saelee <me AT kaosaelee DOT com>
*   @license     http://www.gnu.org/copyleft/lesser.html  LGPL License 2.1
*/
class PhpBlogApi_MetaWeblog extends PhpBlogApi_ExtendedDriver
{
    /**
    *   Internal list with user data.
    *   @var array 
    */
    protected $userdata = array();
	
    protected $arSupportedPostProperties = array(
        PhpBlogApi_Post::TITLE,
        PhpBlogApi_Post::CONTENT,
        PhpBlogApi_Post::DATE,
        PhpBlogApi_Post::URL,
        PhpBlogApi_Post::CATEGORIES,
    );
	
	
    /**
    *   Constructor for the metaWeblog driver class.
    *
    *   @param   string  $user       The username of the blog account.
    *   @param   string  $pass       The password of the blog account.
    *   @param   string  $server     The URI of the server to connect to.
    *   @param   string  $path       The path to the XML-RPC server script.
    *
    *   @throws PhpBlogApi_Exception If authentication fails
    */
    public function __construct($user, $pass, $server, $path,$blogId = 0)
    {
        $this->userdata = array(
            'user'  => $user,
            'pass'  => $pass,
            'server'=> $server,
            'path'  => $path,
			'blogId'=> $blogId
        );
		
        $this->rpc_client = new Zend_XmlRpc_Client($server.$path);
		
		//test if we can connect to the XML-RPC server
		try{
			$this->testCall();
		}catch(Exception $e){
			 $message = $e->getMessage();
			 if($message == 'Not Found'){
				 $message = 'Unable to connect to XML-RPC server.';
			 }
			 throw new PhpBlogApi_Exception( $message,$e->getCode());
		}
			
    }//public function __construct($userid, $pass, $server, $path)
	
	
    /**
    *   Save a new post into the blog.
    *
    *   @param PhpBlogApi_Post $post     Post object to put online
    *
    *   @return Array $result  $result['result'] = true on success, false on failure.
	*							$result['response'] = int $postId on success new post or response message
    */
    public function savePost(PhpBlogApi_Post $post,$publish = true)
    {
        if ($post->id === null) {
			try{
				$response =  $this->rpc_client->call('metaWeblog.newPost',array(
																	$this->userdata['blogId'], //blog_id
																	$this->userdata['user'], //username
																	$this->userdata['pass'], //pass
																	self::convertPostToStruct($post),
																	$publish
																));
				
				if(!is_numeric($response)){
					return $this->responseMsg(false,'unable to create new post');	
				}
				
				return $this->responseMsg(true,$response);
			}
			catch(Exception $e)
			{
				return $this->responseMsg(false,$e->getMessage());
			}
			
        } else {
            try{
				$response = $this->rpc_client->call('metaWeblog.editPost',array(
																	$post->id, //post id
																	$this->userdata['user'], //username
																	$this->userdata['pass'], //pass
																	self::convertPostToStruct($post),
																	$publish
																));
				
				if(!$response){
					return $this->responseMsg(false,'Unable to update post.');	
				}
				
				return $this->responseMsg(true,'Post successfully updated.');
			}
			catch(Exception $e){
				return $this->responseMsg(false,$e->getMessage());
			}
        }
    }//public function savePost(PhpBlogApi_Post $post)
	
    /**
    *   The getPost method is intended to retrive a given post as an object of
    *   the PhpBlogApi_Post class; given the unique post id which is passed
    *   as a parameter to the function.
    *
    *   @param   string  $id         The PostID of the post to be retrieved. (As
    *                               returned by newPost() defined in
    *                               PhpBlogApi_driver).
	*   @return Array $result  $result['result'] = true on success, false on failure.
	*							$result['response'] = PhpBlogApi_Post object or failure message
    */
    public function getPost($id)
    {
		try
		{
			$response = $this->rpc_client->call('metaWeblog.getPost',array(
																		$id, //post id
																		$this->userdata['user'], //username
																		$this->userdata['pass'] //pass
																	));
			if(!empty($response) && $response['postid'] == $id)
			{
				return $this->responseMsg(true,$this->convertStructToPost($response));
			}
		}
		catch(Exception $e)
		{
			return $this->responseMsg(false,$e->getMessage());
		}
		
		
	   return $this->responseMsg(false,'Sorry, the post does not exist.');
    }//public function getPost($id)
	
	
    /**
    *   Delete a given post.
    *   The deletePost method in metaWeblog is just
    *    an alias to the deletePost blogger method
    *
    *   @param mixed  $post   PhpBlogApi_Post object to delete,
    *                           or post id (integer) to delete
	*
    *   @return Array $result  $result['result'] true on success, false on failure.
	*							$result['response'] response message
    */
    public function deletePost($post)
    {
        if (!($post instanceof PhpBlogApi_Post)) {
            $nPostId = $post;
            $post = new PhpBlogApi_Post();
            $post->setId($nPostId);
        }
		try
		{
			$response = $this->rpc_client->call('metaWeblog.deletePost',array(
																		123, //dummy app key - this value is ignored
																		$post->id, //post id
																		$this->userdata['user'], //username
																		$this->userdata['pass'], //pass
																		true //publish - this value is ignored
																	));
			if($response)
			{
				return $this->responseMsg(trye,'Post successfully deleted.');	
			}
		}
		catch(Exception $e)
		{
			return $this->responseMsg(false,$e->getMessage());
		}
		
	   return $this->responseMsg(false,'Sorry, the post does not exist.');
    }//public function deletePost($post)
	
    /**
    *   Returns an array of recent posts as PhpBlogApi_Post objects
    *
    *   @param   int     $number     The number of posts to be retrieved.
    *                                    Defaults to 15
    *   @return Array $result  $result['result'] = true on success, false on failure.
	*							$result['response'] = Array of PhpBlogApi_Post objects on success or response message
    */
    public function getRecentPosts($number = 15)
    {
		try
		{
			$response = $this->rpc_client->call('metaWeblog.getRecentPosts',array(
																		$this->userdata['blogId'], //blog id
																		$this->userdata['user'], //username
																		$this->userdata['pass'], //pass
																		$number
																	));
			$arPosts = array();
			
			if(!empty($response))
			{
				foreach ($response as $data) {
					$post = $this->convertStructToPost($data);
					$arPosts[$post->id] = $post;
				}
				
				return $this->responseMsg(true,$arPosts);
			}
		}
		catch(Exception $e)
		{
			return $this->responseMsg(false,$e->getMessage());
		}
		
		
	   return $this->responseMsg(false,'Sorry, unable to retrieve recent posts.');
    }//public function getRecentPosts($number = 15)
	
	
    /**
    *   The getRecentPostTitles method is intended to retrieve the given number of
    *   posts titles from a blog.
    *   The posts themselves can be retrieved with getPost() or getRecentPosts().
    *
    *   There is no direct getRecentPostTitles method in metaWeblog. So
    *   we internally call getRecentPosts() and strip out ids and titles of
    *   the post. So this method is slow here, because all post data needs
    *   to be transmitted.
    *
    *   @param   int     $number     The number of posts to be retrieved.
    *
	 *   @return Array $result  $result['result'] = true on success, false on failure.
	*							$result['response'] = Array of post ids (key) and their title (value) on success or response message
    */
    public function getRecentPostTitles($number = 15)
    {
        $result = $this->getRecentPosts($number);
        $arTitles = array();
		
		if($result['result']){
			
			foreach ($result['response'] as $post) {
				$arTitles[$post->id] = $post->{PhpBlogApi_Post::TITLE};
			}
			
			return $this->responseMsg(true,$arTitles);
		}
		else
		{
			return $this->responseMsg(false,'Unable to retrieve recent post titles.');
		}
    }//public function getRecentPostTitles($number = 15)
	
	
    /**
    *   Returns an array of strings thay define
    *   the properties that a post to this blog may
    *   have.
    *
    *   @return array   Array of strings
    */
    public function getSupportedPostProperties()
    {
        return $this->arSupportedPostProperties;
    }//public function getSupportedPostProperties()
	
	
    /**
    *   Checks if the given property name/id is supported
    *   for this driver.
    *
    *   @param string $strProperty  Property name/id to check
    *
    *   @return boolean     If the property is supported
    */
    public function isPostPropertySupported($strProperty)
    {
        return in_array($strProperty, $this->arSupportedPostProperties);
    }//public function isPostPropertySupported($strProperty)
	
	
    /**
    *   Converts a struct returned by the webservice to
    *   a PhpBlogApi_Post object
    *
    *   @param array    $arStruct   Struct to convert
    *   @return PhpBlogApi_Post  Converted post
    */
    protected function convertStructToPost($arStruct)
    {
        $post = new PhpBlogApi_Post($this);
        $post->{PhpBlogApi_Post::CONTENT} = $arStruct['description'];
        $post->{PhpBlogApi_Post::TITLE}   = $arStruct['title'];
        //0123456789012345678
        //20060514T09:19:33
        $post->{PhpBlogApi_Post::DATE}    = mktime(
            substr($arStruct['dateCreated'],  9, 2),//hour
            substr($arStruct['dateCreated'], 12, 2),//minute
            substr($arStruct['dateCreated'], 15, 2),//second
            substr($arStruct['dateCreated'],  4, 2),//month
            substr($arStruct['dateCreated'],  6, 2),//day
            substr($arStruct['dateCreated'],  0, 4)//year
        );
        $post->{PhpBlogApi_Post::URL}        = $arStruct['link'];
        if (!isset($arStruct['categories'])) {
            $arStruct['categories'] = array();
        }
        $post->{PhpBlogApi_Post::CATEGORIES} = $arStruct['categories'];
        $post->setId($arStruct['postid']);
        return $post;
    }//protected function convertStructToPost($arStruct)
	
	
    /**
    *   Converts PhpBlogApi_Post object to
    *   an XML-RPC struct that can be sent to the server.
    *
    *   @param PhpBlogApi_Post  $post    Post object to convert
    *   @param XML_RPC_Value    Struct to send
    */
    protected function convertPostToStruct($post)
    {
        $time = $post->{PhpBlogApi_Post::DATE};
        if ($time == ''  || $time == 0) {
            $time = time();
        }
       
	   $categories = $post->{PhpBlogApi_Post::CATEGORIES};
        if (!is_array($categories)) {
            $categories = array();
        } else {
            $catstr = $categories;
            $categories = array();
            foreach ($catstr as $cat) {
                $categories[] = $cat;
            }
        }
		
		return array(
                'category'  => $categories,
                'pubDate' => date('Ymd\\TH:i:s', $time),
                'description' => $post->{PhpBlogApi_Post::CONTENT},
                'title'       => $post->{PhpBlogApi_Post::TITLE}
            );
    }//protected function convertPostToStruct($post)
	
	/**
	*   test call if we are able to connect to the XML-RPC server
    *
    *   @return boolean $result   Returns true if able to retrieve posts
	*
	*	 @throws PhpBlogApi_Exception If authentication fails or cannot connect to server
    */
    public function testCall()
    {
		$response = $this->rpc_client->call('metaWeblog.getRecentPosts',array(
																		$this->userdata['blogId'], //blog id
																		$this->userdata['user'], //username
																		$this->userdata['pass'], //pass
																		1
																	));
		return true;
    }//public function testCall()
	
	/**
    *   Returns the response result pagee
    *
    *   @param boolean $result if the result was a success(true) or failure(false)
    *	@param string $message the message to return along with the result
	*
    *   @throws PhpBlogApi_Exception If an error occured
    */
	public function responseMsg($result,$message)
	{
		return array('result'=>$result,'response'=>$message);
	}//public function responseMsg($result,$message)
	
}//class PhpBlogApi_Driver_MetaWeblog extends PhpBlogApi_ExtendedDriver
?>